'''
Created on Mar 13, 2013

@author: pb
'''

import logging
import importlib
import time
import datetime
import env
    
log = logging.getLogger(__name__)

class Data:
    

    INSERT_MEASURING = 'insert into measuring (hwid, place, ctime, value, unit, dtype) values (:hwid, :place, :ctime, :value, :unit, :dtype)'
    
    def __init__(self):
        log.debug("initializing...")
        pass
        
       
    
    def detectors(self, hwid=None, place=None):
        out = []
        p = {}
        if (hwid): p['hwid'] = hwid
        if (place): p['place'] = place
        with env.RestQuery("select * from detector", p) as q:
            for i in  q.fetchall():
                d = Detector(i['hwid'], i['dtype'], i['place'])
                d.unit = i['unit']
                d.ctime = time.gmtime(i['ctime'])
                d.mtime = time.gmtime(i['mtime'])
                
                out.append(d)
        return out    
        
            
    def save_measure(self, detector):
        log.debug("saving: %s" % detector)
        with self.conn:
            c = self.conn.cursor()
            c.execute(self.INSERT_MEASURING, {'hwid': detector.hwid, 'dtype': detector.dtype, 'place': detector.place, 'unit': detector.unit, 'ctime': time.mktime(detector.ctime.timetuple()), 'value': detector.value});
            self.conn.commit()
     
    def get_measures(self, timeoffset=None, end=None): 
        out = []
        p = {}
        if (timeoffset): p['timeoffset'] =  time.mktime(timeoffset.timetuple)
        if (end): p['end'] =  time.mktime(end.timetuple)
        with env.RestQuery("select * from measuring", p) as q:
            for i in q.fetchall():
                try:
                    m = Measuring(i['hwid'], i['dtype'], i['place'])
                    m.ctime = time.gmtime(i['ctime'])
                    m.value = i['value']
                    out.append(m)
                except Exception:
                    log.error("reading : %s" % i)
        return out    
      
      
    def save_detector(self, detector):
        log.debug("saving detector: %s" % detector)
        
        upd = "update detector set  dtype=:dtype, unit=:unit, mtime=:mtime where hwid=:hwid and place=:place"
        pk = {'hwid': detector.hwid, 'place': detector.place}
        
        with env.Db() as db:
            log.debug("db: %s" % db)
            conn = db.get_connection()
            c  = conn.cursor()
            if (not(c.execute("select count(*) as count from detector where place=:place and hwid=:hwid", pk).fetchone()['count'])):
                log.debug("inserting new ")
                c.execute("insert into detector (hwid,place,dtype) values (:hwid,:place, '?')", pk)
            pk.update({'dtype': detector.dtype, 'unit': detector.unit, 'mtime': int(time.mktime(datetime.datetime.now().timetuple()))})   
            c.execute(upd, pk)  
            conn.commit()
            
       
    def aggregate_max(self, cursor):
        cursor.execute("select hwid,place,dtype,value, null as count, ctime, unit, 'X' as atype from t-aggr where value=max(value)")
        pass
    
    def aggregate_min(self, cursor):
        pass
          
          
class Agregate(): 
    
    INSERT_QUERY = "insert into measuring_agr (hwid,place,dtype,unit, value,duration,count, atype) values (:hwid,:place,:dtype,:unit,:value,:count,:atype)"
     
    SELECT_QUERY = "select * from measuring where hwid=:hwid and place=:place and dtype=:dtype and unit=:unit and ctime<:endpoint order by ctime desc" 
    
    
    def __init__(self, endpoint, hwid,place,dtype, unit=None):
        log.debug("Agregate.__init__")
        self.enpoint = endpoint
        self.hwid = hwid
        self.place = place
        self.dtype = dtype
        self.unit = unit
        
    def sel(self, cursor):
        return cursor.execute(self.SELECT_QUERY, {'endpoint': self.endpoint, 'hwid': self.hwid, 'place': self.place, 'dtype': self.dtype, 'unit': self.unit})
    
    def run(self, cursor):
        cursor.executemany(self.INSERT_QUERY, self.agregate(self.sel()))
    

class AgregateMinMax(Agregate):
    
     
    def agregate(self,measurings):
        
        out = []
        m = measurings[0]['value']
        x = m
        for i in measurings:
            v = i['value']
            if (v < m): 
                m = v
                out = [{'value': m, 'count': 1, 'atype': 'N', 'duration': None, 'ctime': i['ctime']}]
            else:
                if (v == m):
                    out.append({'value': m, 'count': 1, 'atype': 'N', 'duration': None, 'ctime': i['ctime']}) 
            if (v > x): 
                x = v
                out = [{'value': x, 'count': 1, 'atype': 'X', 'duration': None, 'ctime': i['ctime']}]
            else:
                if (v == x):
                    out.append({'value': x, 'count': 1, 'atype': 'X', 'duration': None, 'ctime': i['ctime']})             
        return out
        
class AgregateAvg(Agregate):
    
    def agregate(self, measuring_list):
        """
        measuring_list:  list of  value, ctime ordered by ctime (desc), last is first
        """
        
        v = self.endpoint
        m = 0
        for i in measuring_list:
            m += (i['value']  * (v - i['ctime']))
            v = i['ctime']
        return {'ctime':v, 'duration':(self.endpoint - v),  'value:':(m / (self.endpoint - v)), 'count':len(measuring_list), 'atype': 'A'}    
        
        
        

class Measuring:

    def __init__(self,hwid,dtype,place, unit=None, ctime=None, value=None):
        self.hwid = hwid
        self.dtype = dtype
        self.place = place
        self.ctime = ctime
        self.value = value
        self.unit = unit
                 
    def __repr__(self):   
        return "<Measuring hwid=%s,place=%s,unit=%s,value=%s,ctime=%s>" % (self.hwid, self.place, self.unit, self.value, self.ctime)

    
        
         
class Detector:
    
    def __init__(self,hwid, dtype, place):
        self.hwid = hwid
        self.place = place
        self.dtype = dtype
        self.reader = importlib.import_module('reader.%s' % dtype)
        self.unit = None
        self.ctime = None
        self.mtime = None
        
    def __repr__(self):
        return "<Detector hwid=%s,place=%s,dtype=%s,unit=%s,ctime/mtime=%s/%s,reader=%s>" % (self.hwid, self.place, self.dtype, self.unit, self.ctime, self.mtime, self.reader)
        
    def measure(self):    
        m = Measuring(self.hwid,self.dtype,self.place)
        self.reader.measure(m)
        return m   
    
    def __eq__(self, other):
        return (self.hwid, self.place, self.dtype, self.unit) == (other.hwid, other.place, other.dtype, other.unit)
    
    def __hash__(self):
        return hash((self.hwid, self.place, self.dtype, self.unit))
    
    
    
if __name__ == '__main__':
    logging.basicConfig(level=logging.DEBUG)
    


    data = Data()
    
    d = Detector("Ab.X", "owfs", "sever")
    d.measure()
    d.value = 1.1
    d.unit = 'C'
    data.save_detector(d)
    
    print(data.detectors())
    print(data.get_measures())
    
    #env  = env.Environment
    
    """
    with env.CommitQuery("select * from detector") as  q:
        log.debug(q.fetchall())
    """
    pass